#include "satellitalimage.h"


/*
    Constructor sin parametros define la altura y el ancho de la imagen en cero
*/
SatellitalImage::SatellitalImage()
{
    this->height = 0;
    this->width = 0;
}

/*
    Destructor
*/
SatellitalImage::~SatellitalImage()
{
}

/*

*/
QVariant SatellitalImage::getNumericValueOf(int beginIndex, QString data)
{
    bool endValue = false;
    QString value = "";

    for (int i = beginIndex; !endValue && (i < data.length()); i++){
        QChar c = data.at(i);
        if (((c < 58) && (c > 47)) || (c == 45))
            value += c;
        else
            endValue = true;
    }
    return QVariant(value);
}

/*
    Este metodo genere una imagen en RGB dado como parametro las 3 bandas que el usuario desea
*/
QImage SatellitalImage::getFalseColorPreviewOf(unsigned short int redIndex, unsigned short int greenIndex, unsigned short int blueIndex, QSize imgSize)
{
    QImage img(imgSize,QImage::Format_RGB32);

    QFile *archR = new QFile(this->bandsPaths.at(redIndex-1));
    QFile *archG = new QFile(this->bandsPaths.at(greenIndex-1));
    QFile *archB = new QFile(this->bandsPaths.at(blueIndex-1));

    if (archR->open(QIODevice::ReadOnly) && archG->open(QIODevice::ReadOnly) && archB->open(QIODevice::ReadOnly))
    {
        char infR[10000];
        char infG[10000];
        char infB[10000];

        int j = 0;
        int k = 0;
        int incWidth = this->width/imgSize.width();
        int incHeight = this->height/imgSize.height();

        archR->seek(0);
        archG->seek(0);
        archB->seek(0);


        while (k < imgSize.height())
        {
            archR->read(infR,(qint64)this->width);
            archG->read(infG,(qint64)this->width);
            archB->read(infB,(qint64)this->width);
            int i = 0;
            int l = 0;

            while (l < imgSize.width())
            {
                img.setPixel(l,k,qRgb((int)infR[i],(int)infG[i],(int)infB[i]));
                l++;
                i+=incWidth;
            }

            k++;
            j+=incHeight;
            archR->seek((qint64)j*this->width);
            archG->seek((qint64)j*this->width);
            archB->seek((qint64)j*this->width);
        }
    }
    archR->close();
    archG->close();
    archB->close();

    delete archR;
    delete archG;
    delete archB;

    satImage=QImage(img);
    return img;
}

/*
  Este metodo se utiliza para clasificar la imagen dado un vector de valores de firma espectral
  @params

*/
void SatellitalImage::doClasify(QVector<int> reg)
{
    int i,j=0;
    for (i=0; i<this->satImage.width(); i++)
        for (j=0; j<this->satImage.height(); j++)
            if (betweenSpectralFirm(this->getSpectralSignatureOf(QPoint(i,j),QSize(this->satImage.width(),this->satImage.height())),reg));
                doHighlight(QPoint(i,j));
}
/*
  Este metodo se utiliza para clasificar la imagen dado un vector de valores de firma espectral
  @params

*/
void SatellitalImage::doRegionGrowing(QPoint point)
{
    QVector<int> truthspectralfirm= this->getSpectralSignatureOf(point,QSize(this->getWidth(),this->getHeight()));

    QVector<int> spectralfirm1= this->getSpectralSignatureOf(QPoint(point.x()-1,point.y() -1),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm2= this->getSpectralSignatureOf(QPoint(point.x(),point.y()-1),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm3= this->getSpectralSignatureOf(QPoint(point.x()+1,point.y()-1),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm4= this->getSpectralSignatureOf(QPoint(point.x()-1,point.y()),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm5= this->getSpectralSignatureOf(QPoint(point.x()+1,point.y()),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm6= this->getSpectralSignatureOf(QPoint(point.x()-1,point.y()+1),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm7= this->getSpectralSignatureOf(QPoint(point.x(),point.y()+1),QSize(this->getHeight(),this->getWidth()));
    QVector<int> spectralfirm8= this->getSpectralSignatureOf(QPoint(point.x()+1,point.y()+1),QSize(this->getHeight(),this->getWidth()));

    if (betweenSpectralFirm(spectralfirm1,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm2,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm3,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm4,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm5,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm6,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm7,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));
    if (this->betweenSpectralFirm(spectralfirm8,truthspectralfirm))
        doRegionGrowing(QPoint(point.x()-1,point.y() -1));

    doHighlight(point);

}

QImage SatellitalImage::getImage()
{
    return satImage;
}

/*
  Resalta con rojo los pixeles que forman parte del region growing
  */
void SatellitalImage::doHighlight(QPoint point)
{
    satImage.setPixel(point.x(),point.y(),qRgb(255,0,0));
}

/*
    NECESITO METODO PARA COMPARAR FIRMAS ESPECTRALES
*/
bool SatellitalImage::betweenSpectralFirm(QVector<int> firm1,QVector<int> firm2)
{
    bool between =true;
    if ((firm1.size()==7) and (firm2.size()==14))
    {
        int j=0;
        for (int i=0; i<7 and between;i++)
        {
            if ((firm1[i]> firm2[j]) and (firm1[i]<firm2[j+1]))
                j=i+2;
            else
                    between=false;
        }
    }
                return between;
}

/*
    Este metodo obtiene una imagen en escala de grises dado una banda
*/
QImage SatellitalImage::getGrayPreviewOf(unsigned short int bandIndex, QSize imgSize)
{
    QImage img(imgSize,QImage::Format_RGB32);

    QFile *archG = new QFile(this->bandsPaths.at(bandIndex-1));

    if (archG->open(QIODevice::ReadOnly))
    {
        char inf[10000];

        int j = 0;
        int k = 0;
        int incWidth = this->width/imgSize.width();
        int incHeight = this->height/imgSize.height();

        archG->seek(0);

        while (k < imgSize.height())
        {
            archG->read(inf,(qint64)this->width);
            int i = 0;
            int l = 0;

            while (l < imgSize.width())
            {
                img.setPixel(l,k,qRgb((int)inf[i],(int)inf[i],(int)inf[i]));
                l++;
                i+=incWidth;
            }

            k++;
            j+=incHeight;
            archG->seek((qint64)j*this->width);
        }
    }
    archG->close();

    delete archG;
    satImage=QImage(img);
    return img;
}

/*
    Este metodo se encarga de obtener la firma espectral de un pixel dado
    @params
        imgCoordinates: las coordenadas del pixel
        imgSize: el tamaño real de la imagen, puede ser que tenga aplicado un zoom
*/
QVector<int> SatellitalImage::getSpectralSignatureOf(QPoint imgCoordinates, QSize imgSize)
{
    QVector<int> spectralSignature;
    int incWidth = this->width/imgSize.width();
    int incHeight = this->height/imgSize.height();

    for (int i=0; i < this->bandsPaths.size(); i++)
    {
        QFile *arch = new QFile(this->bandsPaths.at(i));

        if (arch->open(QIODevice::ReadOnly))
        {
            char inf[10000];
            arch->seek((qint64)imgCoordinates.y() * incHeight * this->width);
            arch->read(inf,(qint64)this->width);
            spectralSignature << inf[imgCoordinates.x()*incWidth];
        }

        arch->close();
        delete arch;
    }

    return spectralSignature;
}

/*
    Devuelve el alto de la imgaen
*/
int SatellitalImage::getHeight()
{
    return this->height;
}

/*
    Devuelve el ancho de la imagen
*/
int SatellitalImage::getWidth()
{
    return this->width;
}
